///////////////////////////////////////////////////////////////////////////
//
// Spring Engine Source File.
// Copyright (C), Dengtao 2011-2021
// ----------------------------------------------------------------------
// File name:   SfNotificationCenter.cpp
// Version:     v1.0.0
// Created:     2013/06/21 22:54 by dengtao
// Compilers:   Visual Studio 2008
// Description: 
// ----------------------------------------------------------------------
// History:
//
///////////////////////////////////////////////////////////////////////////

#include "SfNotificationCenter.h"
#include <algorithm>

namespace Sunflower
{
//
//Summary:
//	Constructor.
NotificationCenter::NotificationCenter()
	: m_LastUpdateTime(0)
{
}

//
//Summary:
//	Destructor.
NotificationCenter::~NotificationCenter()
{

}

//
//Summary:
//	Add a notification observer.
void NotificationCenter::AddObserver(unsigned int notificationId, 
	const NotificationHandleDelegate& nhd)
{
	if (Notification::IsValidId(notificationId))
	{
		ObserverList& ol = m_Observers[notificationId];

		if (_FindObserverInList(ol, nhd) != ol.end())
		{
			ol.push_back(nhd);
		}
	}
}

//
//Summary:
//	Remove a notification observer.
void NotificationCenter::RemoveObserver(unsigned int notificationId, 
	NotificationHandleDelegate& nhd)
{
	ObserverMapIterator omi = m_Observers.find(notificationId);

	if (omi == m_Observers.end())
	{
		return;
	}

	ObserverList& ol = omi->second;
	ObserverListIterator olit = _FindObserverInList(ol, nhd);

	if (olit != ol.end())
	{
		ol.erase(olit);
	}
}

//
//Summary:
//	Remove all notification observers.
void NotificationCenter::RemoveAllObservers()
{
	m_Observers.clear();
}

//
//Summary:
//	find observer iterator.
NotificationCenter::ObserverListIterator 
NotificationCenter::_FindObserverInList(
	NotificationCenter::ObserverList& ol,
	const NotificationHandleDelegate& nhd)
{
	return std::find(ol.begin(), ol.end(), nhd);
}

NotificationCenter::ObserverListConstIterator 
NotificationCenter::_FindObserverInList(
	const NotificationCenter::ObserverList& ol,
	const NotificationHandleDelegate& nhd) const
{
	return std::find(ol.begin(), ol.end(), nhd); 
}

//
//Summary:
//	Post immediate notification.
void NotificationCenter::PostNotification(const Notification& notification)
{
	if (!Notification::IsValidId(notification.GetId()))
	{
		return;
	}

	ObserverMapIterator omi = m_Observers.find(notification.GetId());

	if (omi == m_Observers.end())
	{
		return;
	}
	
	ObserverList& ol = omi->second;
	_PostNotificationToObserversInList(ol, notification);
}

//
//Summary:
//	_PostNotificationToObserversInList
void NotificationCenter::_PostNotificationToObserversInList(ObserverList& ol, 
	const Notification& notification)
{
	for (ObserverListIterator olit = ol.begin(); 
		 olit != ol.end();
		 ++olit)
	{
		(*olit)(notification);
	}
}

//
//Summary:
//	Post delayed notification.
void NotificationCenter::PostDelayedNotification(
	const Notification& notification, 
	float delayTime)
{
	m_DelayedNotifications.push_back(
		DelayedNotification(notification, delayTime, m_LastUpdateTime));
}

//
//Summary:
//	Update time.
void NotificationCenter::UpdateTime(float deltaTime)
{
	m_LastUpdateTime = m_LastUpdateTime + deltaTime;
}

//
//Summary:
//	Update all delayed notifications.
void NotificationCenter::UpdateAllDelayedNotifications()
{
	DelayedNotificationListIterator dnlit = m_DelayedNotifications.begin();

	for (; dnlit != m_DelayedNotifications.end();)
	{
		DelayedNotificationListIterator it_cur = dnlit;
		++dnlit;

		DelayedNotification& dn = *it_cur;

		if (dn.m_DelayTime + dn.m_PostTime <= m_LastUpdateTime)
		{
			// time out.
			PostNotification(dn.m_Notification);
		}
	}
}

} // end of namespace Sunflower
